package org.web.accesscontrollist.sdk.helper;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.web.accesscontrollist.sdk.dto.*;
import org.web.accesscontrollist.sdk.dto.redundancy.DetailRedundancyDTO;
import org.web.accesscontrollist.sdk.dto.redundancy.TypeRedundancyDTO;
import org.web.base.domain.UpdateGroup;
import org.web.base.domain.exception.ResultMessageEnum;
import org.web.base.domain.helper.ServiceExceptionHelper;
import org.web.base.domain.helper.ValidationHelper;

import jakarta.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;

public class AclHelper {

    /**
     * 校验数据信息
     * 校验内容：
     * 1、@see AclResourceTypeBatchDTO , AclResourceTypeBatchDTO.class定义的数据格式。
     * 2、@see AclResourceTypeDTO , 遍历 List<AclResourceTypeDTO> aclResourceTypeDTOList ， 校验每个AclResourceTypeDTO对象。
     * 3、aclResourceTypeDTOList 中的typeName不能够重复。
     * 4、AclResourceTypeDTO 如果aclResourceTypeDTO.getMaxLevel() 大于零，则校验Level的合法性。
     */
    public static void checkSaveAclResourceTypeBatchDTO(AclResourceTypeBatchDTO aclResourceTypeBatchDTO, Class clazz) {
        ValidationHelper.validateWithThrow(AclResourceTypeBatchDTO.class, aclResourceTypeBatchDTO);
        OperatorDTO operatorDTO = aclResourceTypeBatchDTO.getOperatorDTO();
        ValidationHelper.validateWithThrow(OperatorDTO.class, operatorDTO);
        List<String> errorList = new ArrayList<>();
        int i = 0;

        List<String> duplicateList = new ArrayList<>();
        List<String> distinctResourceTypeNameList = new ArrayList<>();
        for (AclResourceTypeDTO aclResourceTypeDTO : aclResourceTypeBatchDTO.getAclResourceTypeDTOList()) {
            i++;
            if (aclResourceTypeDTO != null) {
                aclResourceTypeDTO.setBusinessLine(operatorDTO.getBusinessLine());
                aclResourceTypeDTO.setOperatorNum(operatorDTO.getOperatorNum());
                aclResourceTypeDTO.setOperatorName(operatorDTO.getOperatorName());
                aclResourceTypeDTO.setExecuteSuccess(false);
                if (clazz == null) {
                    clazz = UpdateGroup.class;
                }
                String error = ValidationHelper.validateResturnString(AclResourceTypeBatchDTO.class, aclResourceTypeBatchDTO, clazz);
                if (StringUtils.isNotBlank(error)) {
                    errorList.add("第" + i + "记录信息不合法：" + error);
                } else {
                    if (aclResourceTypeDTO.getMaxLevel() != null || aclResourceTypeDTO.getFirstLevelAlias() != null || aclResourceTypeDTO.getSecondLevelAlias() != null || aclResourceTypeDTO.getThirdLevelAlias() != null || aclResourceTypeDTO.getFourthLevelAlias() != null || aclResourceTypeDTO.getFifthLevelAlias() != null) {
                        String[] levels = new String[]{aclResourceTypeDTO.getFirstLevelAlias(), aclResourceTypeDTO.getSecondLevelAlias(), aclResourceTypeDTO.getThirdLevelAlias(), aclResourceTypeDTO.getFourthLevelAlias(), aclResourceTypeDTO.getFifthLevelAlias()};
                        checkLevels(i, errorList, aclResourceTypeDTO.getMaxLevel(), levels);
                    }
                    // aclResourceTypeDTOList 中的typeName不能够重复。
                    String keyName = buildUniqueKeyByAttributes(aclResourceTypeDTO.getBusinessLine(), aclResourceTypeDTO.getTypeName());
                    addIfNotDuplicate(duplicateList, distinctResourceTypeNameList, keyName);
                }
            } else {
                errorList.add("第" + i + "记录信息为空");
            }
        }

        checkRemoveCommon(duplicateList, errorList);
    }

    /**
     * 校验数据信息：
     *
     * @see org.web.accesscontrollist.sdk.helper.AclHelper . checkSaveAclDetailBatchDTO(aclResourceDetailBatchDTO , UpdateGroup.class)
     * 1、@see aclResourceDetailBatchDTO , aclResourceDetailBatchDTO.class定义的数据格式。
     * 2、@see AclResourceDetailDTO , 遍历 List<AclResourceDetailDTO> aclResourceDetailDTOList ， 校验每个AclResourceDetailDTO对象。
     * 3、aclResourceDetailDTOList 中的typeName和detailName组合，不能够重复。businessLine、typeName和detailName组合，逻辑唯一。
     * 4、AclResourceDetailDTO 如果aclResourceDetailDTO.getMaxLevel() 大于零，则校验Level的合法性。
     */
    public static void checkSaveAclDetailBatchDTO(AclResourceDetailBatchDTO aclResourceDetailBatchDTO, Class clazz) {
        ValidationHelper.validateWithThrow(AclResourceDetailBatchDTO.class, aclResourceDetailBatchDTO);
        ValidationHelper.validateWithThrow(OperatorDTO.class, aclResourceDetailBatchDTO.getOperatorDTO());

        List<String> errorList = new ArrayList<>();
        OperatorDTO operatorDTO = aclResourceDetailBatchDTO.getOperatorDTO();
        List<String> duplicateList = new ArrayList<>();
        List<String> distinctList = new ArrayList<>();
        int i = 0;
        for (AclResourceDetailDTO aclResourceDetailDTO : aclResourceDetailBatchDTO.getAclResourceDetailDTOList()) {
            i++;
            if (aclResourceDetailDTO != null) {
                aclResourceDetailDTO.setBusinessLine(operatorDTO.getBusinessLine());
                aclResourceDetailDTO.setOperatorNum(operatorDTO.getOperatorNum());
                aclResourceDetailDTO.setOperatorName(operatorDTO.getOperatorName());
                aclResourceDetailDTO.setExecuteSuccess(false);
                if (clazz == null) {
                    clazz = UpdateGroup.class;
                }
                String error = ValidationHelper.validateResturnString(AclResourceDetailBatchDTO.class, aclResourceDetailBatchDTO, clazz);

                if (StringUtils.isNotBlank(error)) {
                    errorList.add("第" + i + "记录信息不合法：" + error);
                } else {
                    if (aclResourceDetailDTO.getResourceLevel() != null || aclResourceDetailDTO.getFirstLevel() != null || aclResourceDetailDTO.getSecondLevel() != null || aclResourceDetailDTO.getThirdLevel() != null || aclResourceDetailDTO.getFourthLevel() != null || aclResourceDetailDTO.getFifthLevel() != null) {
                        String[] levels = new String[]{aclResourceDetailDTO.getFirstLevel(), aclResourceDetailDTO.getSecondLevel(), aclResourceDetailDTO.getThirdLevel(), aclResourceDetailDTO.getFourthLevel(), aclResourceDetailDTO.getFifthLevel()};
                        checkLevels(i, errorList, aclResourceDetailDTO.getResourceLevel(), levels);
                    }
                    // aclResourceTypeDTOList 中的typeName不能够重复。
                    String keyName = buildUniqueKeyByAttributes(aclResourceDetailDTO.getBusinessLine(), aclResourceDetailDTO.getTypeName(), aclResourceDetailDTO.getDetailName());
                    addIfNotDuplicate(duplicateList, distinctList, keyName);
                }
            } else {
                errorList.add("第" + i + "记录信息为空");
            }
        }

        checkRemoveCommon(duplicateList, errorList);
    }


    public static void checkSaveAclResourceUserBindingBatchDTO(AclResourceUserBindingBatchDTO aclResourceUserBindingBatchDTO, Class clazz) {
        ValidationHelper.validateWithThrow(AclResourceUserBindingBatchDTO.class, aclResourceUserBindingBatchDTO);
        ValidationHelper.validateWithThrow(OperatorDTO.class, aclResourceUserBindingBatchDTO.getOperatorDTO());

        List<String> errorList = new ArrayList<>();
        OperatorDTO operatorDTO = aclResourceUserBindingBatchDTO.getOperatorDTO();
        List<String> duplicateList = new ArrayList<>();
        List<String> distinctList = new ArrayList<>();
        int i = 0;
        for (AclResourceUserBindingDTO aclResourceUserBindingDTO : aclResourceUserBindingBatchDTO.getAclResourceUserBindingDTOList()) {
            i++;
            if (aclResourceUserBindingDTO != null) {
                aclResourceUserBindingDTO.setBusinessLine(operatorDTO.getBusinessLine());
                aclResourceUserBindingDTO.setOperatorNum(operatorDTO.getOperatorNum());
                aclResourceUserBindingDTO.setOperatorName(operatorDTO.getOperatorName());
                if (clazz == null) {
                    clazz = UpdateGroup.class;
                }
                aclResourceUserBindingDTO.setExecuteSuccess(false);
                String error = ValidationHelper.validateResturnString(AclResourceUserBindingDTO.class, aclResourceUserBindingDTO, clazz);
                if (StringUtils.isNotBlank(error)) {
                    errorList.add("第" + i + "记录信息不合法：" + error);
                } else {
                    // aclResourceUserBindingDTO 不能够重复。
                    String keyName = AclHelper.buildUniqueKeyByAttributes(aclResourceUserBindingDTO.getBusinessLine(), aclResourceUserBindingDTO.getTypeName(), aclResourceUserBindingDTO.getDetailName(), aclResourceUserBindingDTO.getUserNum(), aclResourceUserBindingDTO.getRoleName());
                    addIfNotDuplicate(duplicateList, distinctList, keyName);
                }
            } else {
                errorList.add("第" + i + "记录信息为空");
            }

        }

        checkRemoveCommon(duplicateList, errorList);
    }


    private static void checkRemoveCommon(List<String> duplicateList, List<String> errorList) {
        if (!duplicateList.isEmpty()) {
            errorList.add("typeName存在重复，重复的typeName有" + String.join(",", duplicateList));
        }

        if (ObjectUtils.isNotEmpty(errorList)) {
            throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.PARAM_INVALID, errorList);
        }
    }

    private static void addIfNotDuplicate(List<String> duplicateList, List<String> list, String element) {
        if (!list.contains(element)) {
            list.add(element);
        } else {
            duplicateList.add(element);
        }
    }

    private static boolean checkLevels(int i, List<String> errorList, Integer resourceLevel, String[] levels) {

        if (resourceLevel == null) {
            errorList.add("已指定了其他元素，则resourceLevel 不能为空，需要进行指定，并校验格式。");
            return true;
        }

        if (resourceLevel < 0 || resourceLevel > 5) {
            errorList.add("第 " + i + " 条记录，Level 数据设置不合法.范围在【0-5】");
            return true;
        }
        boolean hasError = false;
        for (int level = 0; level < 5; level++) {
            if (level < resourceLevel) {
                if (StringUtils.isBlank(levels[level])) {
                    hasError = true;
                    errorList.add("第 " + i + " 条记录，Level 为 " + level + " 的场合，小于" + resourceLevel + "的级别，数据不能为空。");
                }
            } else {
                if (StringUtils.isNotBlank(levels[level])) {
                    hasError = true;
                    errorList.add("第 " + i + " 条记录，Level 为 " + level + " 的场合，大于" + resourceLevel + "的级别，数据需要设置为空。");
                }
            }

        }
        return hasError;
    }


    // Method to add an element to the list if it's not already present
    public static void addIfNotDuplicate(List<String> list, String element) {
        if (!list.contains(element)) {
            list.add(element);
        }
    }

    private static final String GLOBAL_SEPARATOR = "@";

    public static String buildUniqueKeyByAttributes(String... attributeNames) {
        return String.join(GLOBAL_SEPARATOR, attributeNames);
    }

    /**
     * 验证对象是否合法
     *
     * @param count     指定第几条记录
     * @param errorList 错误数组
     * @param clazz     验证的类
     * @param object    待验证的对象
     * @param groups    验证组
     * @param <T>       泛型类型
     * @return 没有问题，返回false, 校验有问题，返回true.
     */
    public static <T> boolean validate(int count, @NotNull List<String> errorList, Class<T> clazz, T object, Class<?>... groups) {
        String errorInfo = ValidationHelper.validateResturnString(clazz, object, groups);
        if (StringUtils.isNoneBlank(errorInfo)) {
            errorList.add("第" + count + "条数据信息不合法。 " + errorInfo);
            return true;
        }
        return false;
    }

    public static void validateTypeRedundancyDTO(TypeRedundancyDTO typeRedundancyDTO) {
        ValidationHelper.validateWithThrow(SaveParentDTO.class, typeRedundancyDTO, UpdateGroup.class);
        ValidationHelper.validateWithThrow(TypeRedundancyDTO.class, typeRedundancyDTO);
        ValidationHelper.validateWithThrow(OperatorDTO.class, typeRedundancyDTO.getOperatorDTO());
        if (!"N".equals(typeRedundancyDTO.getIsDelete())) {
            if (StringUtils.isEmpty(typeRedundancyDTO.getNewTypeName())) {
                throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.PARAM_INVALID, "newTypeName 不能为空。");
            }
        }
    }

    public static void validateDetailRedundancyDTO(DetailRedundancyDTO detailRedundancyDTO) {
        ValidationHelper.validateWithThrow(SaveParentDTO.class, detailRedundancyDTO, UpdateGroup.class);
        ValidationHelper.validateWithThrow(OperatorDTO.class, detailRedundancyDTO.getOperatorDTO());
        ValidationHelper.validateWithThrow(DetailRedundancyDTO.class, detailRedundancyDTO);
        if (!"Y".equals(detailRedundancyDTO.getIsDelete())) {
            if (detailRedundancyDTO.getResourceLevel() != null || detailRedundancyDTO.getFirstLevel() != null || detailRedundancyDTO.getSecondLevel() != null || detailRedundancyDTO.getThirdLevel() != null || detailRedundancyDTO.getFourthLevel() != null || detailRedundancyDTO.getFifthLevel() != null) {
                List<String> errorList = new ArrayList<>();
                String[] levels = new String[]{detailRedundancyDTO.getFirstLevel(), detailRedundancyDTO.getSecondLevel(), detailRedundancyDTO.getThirdLevel(), detailRedundancyDTO.getFourthLevel(), detailRedundancyDTO.getFifthLevel()};
                checkLevels(1, errorList, detailRedundancyDTO.getResourceLevel(), levels);
                if (!errorList.isEmpty()) {
                    throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.PARAM_INVALID, errorList);
                }
            }
        }
    }

    public static void copyPropertiesIfNotNull(Object dest, Object source) throws Exception {
        // 获取源对象的所有属性名称
        java.util.Map<String, String> describe = BeanUtils.describe(source);
        // 遍历所有属性
        for (java.util.Map.Entry<String, String> entry : describe.entrySet()) {
            String propertyName = entry.getKey();
            // 检查源对象属性值是否为空
            Object propertyValue = BeanUtils.getProperty(source, propertyName);
            if (propertyValue != null) {
                // 设置属性值到目标对象中
                BeanUtils.setProperty(dest, propertyName, propertyValue);
            }
        }
    }
}
